package taskrunner

import (
	"errors"
	"log"
	"os"
	"sync"
	"video_server/scheduler/dbops"
)

// deleteVideo 删除视频
func deleteVideo(vid string) error {
	err := os.Remove(VIDEO_PAHT + vid)

	// 如果错误是 文件不存在，就不返回 err，因为文件可能已经被删除过了

	if err != nil && !os.IsNotExist(err) {
		log.Printf("删除视频出错：%v", err)
		return err
	}

	return nil
}

// VidepClearDispatcher 传输需要删除的id
func VidepClearDispatcher(dc dataChan) error {
	res, err := dbops.ReadVideoDeletionRecord(3)
	if err != nil {
		log.Printf("获取需要清理的视频id 出错：%v", err)
		return err
	}

	if len(res) == 0 {
		return errors.New("没有定时任务数据！")
	}

	// 把需要删除的 视频id ，传入管道
	for _, id := range res {
		dc <- id
	}

	return nil
}

// VideoClearExecutor 具体执行的任务
func VideoClearExecutor(dc dataChan) error {

	// 存放 err 信息
	errMap := &sync.Map{}
	var err error

forloop:
	for {
		select {
		case vid := <-dc:

			// 从需要删除视频的表里面删除记录
			// 这里使用 go 异步删除，是为了提高效率，可以并行执行
			// 可能会出现一种情况，就是 刚删除第一个 id 的时候，后面的 id 还没有来的急删除，就又会从 管道里面 读取出来，造成重复读
			// 影响不大可以不做处理

			// 这里是一个闭包，闭包里面执行的参数时瞬时的，不会保留记录！
			// 闭包的参数最好是传进去，因为闭包直接调用外面的参数时候，不会立即读取这个参数的值，会等到执行到这个参数的时候才会去读取，
			// 就会造成 读取 到的值和我们想的不一致
			go func(id interface{}) {
				// 先删除视频
				if deleteVideoErr := deleteVideo(vid.(string)); deleteVideoErr != nil {
					errMap.Store(id, deleteVideoErr)
					return
				}

				// 删除记录
				if err := dbops.DelVideoDeletionRecord(id.(string)); err != nil {
					errMap.Store(id, err)
					return
				}
			}(vid)

		default:
			break forloop
		}
	}

	// 遍历这个 map 是否有 error
	errMap.Range(func(k, v interface{}) bool {
		err = v.(error)
		if err != nil {
			// 为 false 就会停止当前的遍历
			return false
		}

		return true
	})

	return err
}
